#!/bin/bash

# CompileTeX for BBEdit or TextWrangler
# 
# CompileTeX is a unix shell script for use in combination with BBEdit. It
# allows you to duplicate some TeXShop functionality in BBEdit (in
# particular the use of master documents through the %SourceDoc comment).
# It also allows you to generate draft document without touching the
# master document (by passing \PassOptionsToClass{draft}{your main
# documentclass} to pdflatex before starting the TeX run).
# 
# You may need to adapt the script to your needs. In particular I include
# scripts to generate metapost graphics (and I assume that the figures
# reside in a folder "Figures" next to the master document). I use a
# separate script to translate the metapost figure into pdf if needed.
# 
# Suggested reading if you are really serious about changing these scripts: 
# - The BBEdit manual 
# - Mac OS X in a nutshell (O'Reilly)
# 
# 
# *** Disclaimer ***
# 
# This software is in the public domain, entirely unsupported. It does
# what I need it to do, and is distributed in the hope that it might be
# useful to others. There is no warranty of any kind. I am subscribed to 
# the TeX on Mac OS X mailing list if you are desperate to get help, or 
# have great suggestions for improvements.
# 
# I disclaim all copyrights on these scripts.
# 
# Maarten Sneep.

# You may want to set these variables to your preferred applications

# The pdf viewer
PDFViewerApp="open" # The default TeX viewer
# Other options are:
# PDFViewerApp="open -a TeXniscope" # TeXniscope
# PDFViewerApp="open -a Preview" # Apple's Preview
# PDFViewerApp="open -a 'Adobe Reader 7.0'" # Formerly known as Acrobat Reader
# PDFViewerApp="open -a PostView" # A viewer by MetaObject (http://www.metaobject.com/Products.html)
# PDFViewerApp="open-x11 xterm; gv " # The GhostScript based viewer.
# TeXniscope and PostView will re-open a file when asked to open a file that is 
# already open, allowing screen updates. Preview and Adobe Reader stubornly refuse this 
# (and cannot be coerced with AppleScript for instance).
# gv (and xdvi) will also allow for screen updates, but the calling sequence is a but awkward, 
# since we first need to start X11 with a near bogus command, I'm sorry for 
# the extra xtern you'll get here.

# the preferred editor: BBEdit or TextWrangler
preferred_editor="bbedit" # change to 'edit' if you're using TextWrangler.
# preferred_editor="edit"

# the distiller
Distiller=pstopdf # pstopdf, ps2pdf, ps2pdf12, ps2pdf13, ps2pdf14
# Apple/Adobe distiller: pstopdf # the Apple postscript distiller is licensed from Adobe.
# ps2pdf: ghostscript
# pstopdf??: produce a certain version of pdf

# Some of my figures are too big to be handled by pdftex, 
# use a different technique there. 
# Set this list to your figures where this is the case.
# Requires your TeX fonts to be accessible to Mac OS X.
##! This is very specific to my situation: be careful!
metapost_toobig=""

#####################################################################################
# no user servicable parts below here. 

FIGURE_LATEX=${HOME}/Library/ShellScripts/figure-latex

frontdoc="$2"

# The syntax in TeXShop to open master files with spaces in them requires double 
# quotes around them. We'll add these ourselves, so strip them here.
# To be sure, strip single quotes as well.

# find the real master file (TeXShop 2.0 Style first)
sourcedoc=`awk -F= '/^%!TEX *[Rr]oot/{print $2}' < "$frontdoc"  | tr -d \"\' `

# if the new method didn't give a result, try the old method:
if [ "$sourcedoc" == "" ]; then
    sourcedoc=`grep '^%SourceDoc' "$frontdoc" | sed 's/^%SourceDoc *//' | tr -d \'\" `
fi

frontdocdir=`dirname "$frontdoc"`
frontdocname=`basename "$frontdoc"`

if [ "$sourcedoc" != "" ]
then
	masterdoc="$frontdocdir/$sourcedoc"
	masterdocdir=`dirname "$masterdoc"`
	masterdocname=`basename "$masterdoc"`
else
	masterdoc="$frontdoc"
	masterdocdir="$frontdocdir"
	masterdocname="$frontdocname"
fi

# find master documentclass

docclass=`perl -e 'undef $/; while(<>){if(/\\\\documentclass[^{]*{(.+?)}/){print "$1\n";}}' \
	"$masterdoc"`

# depending on the type, make an action
myCommand=${1##-}

case $myCommand in
	bibtex)
		case "$masterdocname" in
			*.tex)
				pushd "$masterdocdir"
				bibtex "${masterdocname%%.tex}"
				popd
			;;
		esac
	;;
	allfiguresmps)
		case "$masterdocname" in
			*.tex)
				pushd "$masterdocdir/Figures"
				rm *.pdf *.mps
				for source_file in `ls -1 *.mp`
				do
					if [ -z `echo "$metapost_toobig" | grep "${source_file%%.mp}"` ]
					then 
						${FIGURE_LATEX} -mps "$source_file"
					else
						${FIGURE_LATEX} -pdf -special "$source_file"
					fi
				done
				popd
			;;
			*.mp)
				pushd "$masterdocdir"
				rm *.pdf *.mps
				for source_file in `ls -1 *.mp`
				do
					if [ -z `echo "$metapost_toobig" | grep "${source_file%%.mp}"` ]
					then 
						${FIGURE_LATEX} -mps "$source_file"
					else
						${FIGURE_LATEX} -pdf -special "$source_file"
					fi
				done
				popd
			;;
		esac
	;;
	fullcompile)
		case "$masterdocname" in
			*.tex)
				pushd "$masterdocdir"
				# start out with a clean sheet
				rm "${masterdocname%%.tex}.aux" "${masterdocname%%.tex}.out" \
					"${masterdocname%%.tex}.bbl"
				# basic run, under full draft mode (speed!)
				pdflatex -file-line-error-style -interaction=nonstopmode \
					"\PassOptionsToClass{draft}{$docclass}" \
					"\PassOptionsToPackage{draft}{graphicx}" \
					"\PassOptionsToPackage{draft}{graphics}" \
					"\PassOptionsToPackage{draft}{hyperref}" \
					"\input{\"$masterdocname\"}" 
				
				errors=`perl -e 'while(<>){ if ( /^(\\S+?):(\\d+):\\s(.+?)$/s ) { print "$1#$2#$3\\n"; } }' "${masterdocname%%.tex}.log"`
				if [ -z "$errors" ]
				then
					# run bibtex (needed after the clean sheet)
					bibtex "${masterdocname%%.tex}"
					
					# after the bibliography generation at least two runs are needed
					pdflatex -file-line-error-style -interaction=nonstopmode \
						"\PassOptionsToClass{draft}{$docclass}" \
						"\PassOptionsToPackage{draft}{graphicx}" \
						"\PassOptionsToPackage{draft}{graphics}" \
						"\input{\"$masterdocname\"}"
					
					# a run without draft, and noninteractive (there should be no errors though).
					crossrefs=`grep 'Rerun' "${masterdocname%%.tex}.log"`
					if [ "$crossrefs" != "" ]
					then
						pdflatex -file-line-error-style -interaction=nonstopmode "$masterdocname"
					fi
					
					crossrefs=`grep 'Rerun' "${masterdocname%%.tex}.log"`
					if [ -n "$crossrefs" ]
					then
						pdflatex -file-line-error-style -interaction=nonstopmode "$masterdocname"
					fi
					$PDFViewerApp "${masterdocname%%.tex}.pdf"
				else
					errfile=`echo "$error" | awk -F\# '{print $1}'`
					errline=`echo "$error" | awk -F\# '{print $2}'`
					errmsg=`echo "$error" | awk -F\# '{print $3}'`
					beep
					$preferred_editor +$errline "$errfile"
				fi
				popd
			;;
			*)
		esac
	;;
	show)
		case "$masterdocname" in
			*.tex)
				test -f "${masterdoc%%.tex}.pdf" && $PDFViewerApp "${masterdoc%%.tex}.pdf" ;;
			*.mp)
				test -f "${masterdoc%%.mp}.pdf" && $PDFViewerApp "${masterdoc%%.mp}.pdf" ;;
		esac
	;;
	makefigurepdf)
		case "$masterdocname" in
			*.mp)
				pushd "$masterdocdir"
				${FIGURE_LATEX} -pdf "${masterdocname}"
				$PDFViewerApp "${masterdocname%%.mp}.pdf"
				popd
			;;
		esac
	;;
	makefiguremps)
		case "$masterdocname" in
			*.mp)
				pushd "$masterdocdir"
				${FIGURE_LATEX} -pdf -mps "${masterdocname}"
				$PDFViewerApp "${masterdocname%%.mp}.pdf"
				echo "Waiting for the pdfviewer to start up . . ."
				sleep 10
				rm "${masterdocname%%.mp}.pdf"
				popd
			;;
		esac
	;;
	draftfull)
		case "$masterdocname" in
			*.tex)
				pushd $masterdocdir
				if [ "$docclass" == "memoir" ] ; then
					pdflatex -file-line-error-style -interaction=nonstopmode \
						"\PassOptionsToClass{draft}{$docclass}" \
						"\PassOptionsToClass{showtrims}{$docclass}" \
						"\PassOptionsToPackage{draft}{graphicx}" \
						"\PassOptionsToPackage{draft}{graphics}" \
						"\PassOptionsToPackage{draft}{hyperref}" \
						"\input{\"$masterdocname\"}" && $PDFViewerApp "${masterdocname%%.tex}.pdf"
				else
					pdflatex -file-line-error-style -interaction=nonstopmode \
						"\PassOptionsToClass{draft}{$docclass}" \
						"\PassOptionsToPackage{draft}{graphicx}" \
						"\PassOptionsToPackage{draft}{graphics}" \
						"\PassOptionsToPackage{draft}{hyperref}" \
						"\input{\"$masterdocname\"}" && $PDFViewerApp "${masterdocname%%.tex}.pdf"
				fi
				popd
			;;
		esac
	;;
	makeindex)
		case "$masterdocname" in
			*.tex)
				pushd $masterdocdir
				makeindex -c -p any -s "${masterdocname%%.tex}.ist" "${masterdocname%%.tex}.idx"
				popd
			;;
		esac
	;;
	draft)
		case "$masterdocname" in
			*.tex)
				pushd "$masterdocdir"
				if [ "$docclass" == "memoir" ] ; then
					pdflatex -file-line-error-style -interaction=nonstopmode \
						"\PassOptionsToClass{draft}{$docclass}" \
						"\PassOptionsToClass{showtrims}{$docclass}" \
						"\input{\"$masterdocname\"}"
					crossrefs=`grep 'Rerun' "${masterdocname%%.tex}.log"`
					if [ -n "$crossrefs" ]
					then
						pdflatex -file-line-error-style -interaction=nonstopmode \
							"\PassOptionsToClass{draft}{$docclass}" \
							"\PassOptionsToClass{showtrims}{$docclass}" \
							"\input{\"$masterdocname\"}"
					fi
				else
					pdflatex -file-line-error-style -interaction=nonstopmode \
						"\PassOptionsToClass{draft}{$docclass}" \
						"\input{\"$masterdocname\"}"
					crossrefs=`grep 'Rerun' "${masterdocname%%.tex}.log"`
					if [ -n "$crossrefs" ]
					then
						pdflatex -file-line-error-style -interaction=nonstopmode \
							"\PassOptionsToClass{draft}{$docclass}" \
							"\input{\"$masterdocname\"}"
					fi
				fi
				if [ -f "${masterdocname%%.tex}.pdf" ] ; then
					$PDFViewerApp "${masterdocname%%.tex}.pdf"
				fi
				popd
			;;
		esac
	;;
	allfigurespdf)
		case "$masterdocname" in
			*.tex)
				pushd  "$masterdocdir/Figures"
				rm *.pdf *.mps
				for source_file in `ls -1 *.mp`
				do
					if [ -z `echo "$metapost_toobig" | grep "${source_file%%.mp}"` ]
					then 
						${FIGURE_LATEX} -pdf "$source_file"
					else
						${FIGURE_LATEX} -pdf -special "$source_file"
					fi
				done
				popd
				;;
			*.mp)
				pushd $masterdocdir
				rm *.pdf *.mps
				for source_file in `ls -1 *.mp`
				do
					if [ -z `echo "$metapost_toobig" | grep "${source_file%%.mp}"` ]
					then 
						${FIGURE_LATEX} -pdf "$source_file"
					else
						${FIGURE_LATEX} -pdf -special "$source_file"
					fi
				done
				popd
				;;
		esac
	;;
	openmaster)
		if [ -f "$masterdoc" ]
		then
			$preferred_editor "$masterdoc"
		fi
	;;
	openfile)
		if [ -f "$masterdocdir/${4}" ]
		then
			$preferred_editor "$masterdocdir/${4}"
		fi
	;;
	openfiles)
		while [ "${4}" != "" ]
		do
			if [ -f "$masterdocdir/$4" ]
			then
				$preferred_editor "$masterdocdir/$4"
			fi
			shift
		done
	;;
	openlogfile)
		if [ -f "${masterdoc%%.tex}.log" ]
		then
			$preferred_editor "${masterdoc%%.tex}.log"
		fi
	;;
	encrypt)
		pdftk "${masterdocdir}/${masterdocname%%.tex}.pdf" \
			output "${masterdocdir}/${masterdocname%%.tex}.128.pdf" \
			owner_pw "${4}" \
			user_pw "${6}" \
			allow Printing ScreenReaders ModifyAnnotations \
			compress
	;;
	synchronise)
		sourcefile="${frontdoc}"
		line="${4}"
		pdffile="${masterdoc%%.tex}.pdf"
		
		if [ -f "$pdffile" ]
		then
			if [ -n "${sourcefile}" ]
			then
				osascript \
				-e "tell application \"TeXniscope\"" \
				-e "activate" \
				-e "open file ((POSIX file \"$pdffile\") as string)" \
				-e "refresh of the front document" \
				-e "the front document goto line $line of source \"$sourcefile\"" \
				-e "end tell";
			else
				osascript \
				-e "tell application \"TeXniscope\"" \
				-e "activate" \
				-e "open file ((POSIX file \"$file\") as string)" \
				-e "refresh of the front document" \
				-e "end tell";
			fi
		fi
	;;
	make)
		pushd "$masterdocdir"
		FILE="${masterdoc}"
		if [ "$3" = "-target" ]; then
			make "$4"
		else
			make
		fi
		popd
	;;
	dvips)
		pushd "$masterdocdir"
		if [ -f "${masterdoc%%.tex}.dvi" ] ; then
			dvips "${masterdoc%%.tex}.dvi" -o "${masterdoc%%.tex}.ps
			$Distiller "${masterdoc%%.tex}.ps
		else
			echo "${masterdoc%%.tex}.dvi not found"
		fi
		popd
	;;
	dvipdfm)
		pushd "$masterdocdir"
		if [ -f "${masterdoc%%.tex}.dvi" ] ; then
			dvipdfm -o "${masterdoc%%.tex}.pdf" "${masterdoc%%.tex}.dvi"
		else
			echo "${masterdoc%%.tex}.dvi not found"
		fi
		popd
	;;
	pp4)
		case "$masterdocname" in
			*.tex)
				pushd "$masterdocdir"
                pdflatex -file-line-error-style -interaction=nonstopmode "${masterdocname}"
				if [ -f "${masterdocname%%.tex}.pdf" ] ; then
				    ppower4 "${masterdocname%%.tex}.pdf" "${masterdocname%%.tex}.pp4.pdf"
				    mv "${masterdocname%%.tex}.pp4.pdf" "${masterdocname%%.tex}.pdf"
				fi
				popd
			;;
		esac
	;;
	*tex)
		# attempt to support all standard tex formats
		# pdflatex, pdftex, xetex, xelatex, latex, and tex should all be caught by this,
		# as are the 20 or so others installed by default.
		# (bibtex is handled above, and doesn't reach until here.)
		# $myCommand contains $1 without the minus.
		case "$masterdocname" in
			# typeset tex, ltx (kernel sources) and packages.
			*.tex|*.ltx|*.dtx)
				pushd "$masterdocdir"
				$myCommand \
					-file-line-error-style \
					-interaction=nonstopmode \
					"$masterdocname"
				popd
			;;
			*.ins)
				# a latex package installation file may need interation
				osascript -e 'tell application "Terminal" to activate'
				pushd "$masterdocdir"
				$myCommand "$masterdocname"
				popd
			;;
		esac
	;;
	*)
		echo "Command not recognized: $myCommand"
		$preferred_editor -l
		exit 1
	;;
esac

exit 0
